package com.example.abe.diandi.common;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.RectF;
import android.os.Handler;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.widget.ImageView;

/**
 * Created by abe on 17/2/27.
 */
public class TouchScaleImageView extends ImageView {

    private Context mContext;
    private TouchHelper mTouchHelper;
    private boolean isFirst;
    private OnSingleClickListener mSingleClickListener;
    private OnInterceptTouchListener mInterceptListener;

    private ViewPager mVp;

    public TouchScaleImageView(Context context, ViewPager viewpager) {
        super(context);
        init(context);
        mVp = viewpager;
    }

    public TouchScaleImageView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }

    public TouchScaleImageView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init(context);
    }

    private void init(Context context) {
        isFirst = true;
        mContext = context;
        mTouchHelper = new TouchHelper(mContext);
    }

    public boolean onTouchEvent(MotionEvent event) {
        super.onTouchEvent(event);
        mTouchHelper.onTouchEvent(event);
        if (isFirst) {
            isFirst = false;
            setScaleType(ScaleType.MATRIX);
            setMatrixTransform(new Matrix());
        }
        return true;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (isFirst && getDrawable() != null) {
            isFirst = false;
            setScaleType(ScaleType.MATRIX);
            setMatrixTransform(new Matrix());
        }
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        boolean b = mTouchHelper.isInterceptTouch(ev);
        getParent().requestDisallowInterceptTouchEvent(b);
        if (mInterceptListener != null){
            mInterceptListener.OnInterceptTouch(b, ev);
        }
        return super.dispatchTouchEvent(ev);
    }

    public void setSingleClickListener(OnSingleClickListener singleClickListener) {
        mSingleClickListener = singleClickListener;
    }

    public void setInterceptListener(OnInterceptTouchListener interceptListener){
        mInterceptListener = interceptListener;
    }

    private void setMatrixTransform(Matrix matrix) {
        if (matrix == null)
            return;
        if (getDrawable() == null){
            return;
        }

        Matrix m = new Matrix(matrix);
        float scale = Math.min((float) getWidth() / getDrawable().getIntrinsicWidth(),
                (float) getHeight() / getDrawable().getIntrinsicHeight());
        int tX = (int)(getWidth() - getDrawable().getIntrinsicWidth() * scale) / 2;
        int tY = (int)(getHeight() - getDrawable().getIntrinsicHeight() * scale) / 2;
        m.preTranslate(tX, tY);
        m.preScale(scale, scale);
        setImageMatrix(m);
    }

    /**
     * 手势操作类
     */
    private class TouchHelper {

        //图像转化矩阵
        private Matrix mMatrix;

        //用于存放矩阵的9个值
        private final float[] matrixValues = new float[9];

        //缩放包装类
        private ScaleGestureDetector mScaleGestureDetector;
        private MyScaleGestureHelper mScaleGestureHelper;

        //单指滑动手势拦截包装类
        private MySingleTouchInterceptHelper mSingleTouchInterceptHelper;
        private MySingleTouchGestureDetector mSingleTouchInterceptGestureDetector;

        //单指滑动手势包装类
        private MySingleTouchHelper mSingleTouchHelper;
        private MySingleTouchGestureDetector mSingleTouchGestureDetector;

        //双击手势包装类
        private GestureDetector mGestureDetector;
        private MyDoubleClickGestureHelper mDoubleClickHelper;

        //上次手势缩放比例
        private float preScale = 1;

        //当前手势缩放比例
        private float curScale = 1;

        //最大缩放比例
        private static final float SCALE_MAX = 4f;

        //最小缩放比例
        private static final float SCALE_MIN = 1f;

        //是否拦截
        private boolean isIntercept;

        public TouchHelper(Context context) {
            mMatrix = new Matrix();

            mScaleGestureHelper = new MyScaleGestureHelper();
            mScaleGestureDetector = new ScaleGestureDetector(context, mScaleGestureHelper);

            mDoubleClickHelper = new MyDoubleClickGestureHelper();
            mGestureDetector = new GestureDetector(context, mDoubleClickHelper);

            mSingleTouchHelper = new MySingleTouchHelper();
            mSingleTouchGestureDetector = new MySingleTouchGestureDetector(mSingleTouchHelper);

            mSingleTouchInterceptHelper = new MySingleTouchInterceptHelper();
            mSingleTouchInterceptGestureDetector = new MySingleTouchGestureDetector(mSingleTouchInterceptHelper);
        }

        /**
         * 触摸操作
         */
        public boolean onTouchEvent(MotionEvent event) {
            if (mGestureDetector.onTouchEvent(event))
                return true;
            mScaleGestureDetector.onTouchEvent(event);
            mSingleTouchGestureDetector.onTouchEvent(event);
            return true;
        }

        /**
         * 是否拦截触摸操作
         */
        public boolean isInterceptTouch(MotionEvent event) {
            mSingleTouchInterceptGestureDetector.onTouchEvent(event);
            return isIntercept;
        }

        /**
         * 获得当前的缩放比例
         */
        private final float getScale() {
            mMatrix.getValues(matrixValues);
            return matrixValues[Matrix.MSCALE_X];
        }

        /**
         * 在缩放时，进行图片显示范围的控制
         */
        private void checkBorderAndCenterWhenScale() {
            RectF rect = getMatrixRectF();
            float deltaX = 0;
            float deltaY = 0;

            // 如果宽或高大于屏幕，则控制范围
            if (rect.width() >= getWidth()) {
                if (rect.left > 0) {
                    deltaX = -rect.left;
                }
                if (rect.right < getWidth()) {
                    deltaX = getWidth() - rect.right;
                }
            }
            if (rect.height() >= getHeight()) {
                if (rect.top > 0) {
                    deltaY = -rect.top;
                }
                if (rect.bottom < getHeight()) {
                    deltaY = getHeight() - rect.bottom;
                }
            }
            // 如果宽或高小于屏幕，则让其居中
            if (rect.width() < getWidth()) {
                deltaX = getWidth() * 0.5f - rect.right + 0.5f * rect.width();
            }
            if (rect.height() < getHeight()) {
                deltaY = getHeight() * 0.5f - rect.bottom + 0.5f * rect.height();
            }
            mMatrix.postTranslate(deltaX, deltaY);
        }

        /**
         * 根据矩形获得Matrix转化后的矩形的范围
         */
        private RectF getMatrixRectF() {
            RectF rect = new RectF();
            rect.set(0, 0, getWidth(), getHeight());
            mMatrix.mapRect(rect);
            return rect;
        }

        /**
         * 手势包装类监听
         */
        private class MyDoubleClickGestureHelper extends GestureDetector.SimpleOnGestureListener {

            //主线程Handler
            private Handler mUIHandler;

            //正处于自动缩放
            private boolean isAutoScale;

            private MyDoubleClickGestureHelper() {
                mUIHandler = new Handler();
            }

            @Override
            public boolean onSingleTapConfirmed(MotionEvent e) {
                if (isAutoScale)
                    return false;
                if (mSingleClickListener != null) {
                    return mSingleClickListener.onSingleClick();
                }
                return false;
            }

            @Override
            public boolean onDoubleTap(MotionEvent e) {
                if (isAutoScale)
                    return true;
                float x = e.getX();
                float y = e.getY();
                if (getScale() != SCALE_MIN) {
                    mUIHandler.postDelayed(new AutoScaleRunnable(SCALE_MIN, x, y), 16);
                    isAutoScale = true;
                } else {
                    mUIHandler.postDelayed(new AutoScaleRunnable(SCALE_MAX / 2, x, y), 16);
                    isAutoScale = true;
                }
                return true;
            }

            /**
             * 自动缩放的任务
             */
            private class AutoScaleRunnable implements Runnable {
                static final float BIGGER = 1.07f;
                static final float SMALLER = 0.93f;
                private float mTargetScale;
                private float tmpScale;

                /**
                 * 缩放的中心
                 */
                private float mCenterX;
                private float mCenterY;

                /**
                 * 传入目标缩放值，根据目标值与当前值，判断应该放大还是缩小
                 */
                public AutoScaleRunnable(float targetScale, float x, float y) {
                    mTargetScale = targetScale;
                    mCenterX = x;
                    mCenterY = y;
                    if (getScale() < mTargetScale) {
                        tmpScale = BIGGER;
                    } else {
                        tmpScale = SMALLER;
                    }
                }

                @Override
                public void run() {
                    // 进行缩放
                    mMatrix.postScale(tmpScale, tmpScale, mCenterX, mCenterY);
                    checkBorderAndCenterWhenScale();
                    setMatrixTransform(mMatrix);

                    final float currentScale = getScale();
                    if (((tmpScale > 1f) && (currentScale < mTargetScale))
                            || ((tmpScale < 1f) && (mTargetScale < currentScale))) {
                        // 如果值在合法范围内，继续缩放
                        mUIHandler.postDelayed(this, 16);
                    } else {
                        //设置为目标的缩放比例
                        final float deltaScale = mTargetScale / currentScale;
                        mMatrix.postScale(deltaScale, deltaScale, mCenterX, mCenterY);
                        checkBorderAndCenterWhenScale();
                        setMatrixTransform(mMatrix);
                        isAutoScale = false;
                        //设置缩放比例
                        preScale = mTargetScale;
                        curScale = mTargetScale;
                    }
                }
            }
        }

        /**
         * 单指手指拦截帮助类
         */
        private class MySingleTouchInterceptHelper implements OnSingleTouchListener {

            //最近一次操作的相对于屏幕的位置
            private int mLastX, mLastY;

            @Override
            public boolean onTouchDown(MotionEvent event) {
                //相对屏幕位置
                mLastX = (int) event.getRawX();
                mLastY = (int) event.getRawY();
                isIntercept = true;
                return true;
            }

            @Override
            public boolean onTouchMove(MotionEvent event) {
                int sx = (int) event.getRawX() - mLastX;
                int sy = (int) event.getRawY() - mLastY;

                // 判断当前显示状态
                isIntercept = true;
                RectF rect = getMatrixRectF();
                final float viewWidth = getWidth();
                final float viewHeight = getHeight();
                if (Math.abs(sx) > Math.abs(sy)) {
                    if ((rect.left == 0 && sx > 0) || (rect.right == viewWidth && sx < 0)) {
                        //图片左对齐 图片右对齐
                        isIntercept = false;
                    }
                } else {
                    if ((rect.top == 0 && sy > 0) || (rect.bottom == viewHeight && sy < 0)) {
                        //图片上对齐 图片下对齐
                        isIntercept = false;
                    }
                }

                mLastX = (int) event.getRawX();
                mLastY = (int) event.getRawY();

                return true;
            }
        }


        /**
         * 单指操作帮助类
         */
        private class MySingleTouchHelper implements OnSingleTouchListener {

            //最近一次操作的相对于屏幕的位置
            private int mLastX, mLastY;

            @Override
            public boolean onTouchDown(MotionEvent event) {
                //相对屏幕位置
                mLastX = (int) event.getRawX();
                mLastY = (int) event.getRawY();
                return true;
            }

            @Override
            public boolean onTouchMove(MotionEvent event) {
                // 处理拖动
                int sx = (int) event.getRawX() - mLastX;
                int sy = (int) event.getRawY() - mLastY;

                // 判断移动手势
                // 如果宽度小于屏幕宽度，则禁止左右移动
                RectF rectF = getMatrixRectF();
                if (rectF.width() < getWidth()) {
                    sx = 0;
                }
                // 如果高度小于屏幕高度，则禁止上下移动
                if (rectF.height() < getHeight()) {
                    sy = 0;
                }
                mMatrix.postTranslate(sx, sy);
                checkMatrixBounds();
                setMatrixTransform(mMatrix);

                mLastX = (int) event.getRawX();
                mLastY = (int) event.getRawY();

                return true;
            }

            /**
             * 移动时的边界判断
             */
            private void checkMatrixBounds() {
                RectF rect = getMatrixRectF();
                float deltaX = 0, deltaY = 0;
                final float viewWidth = getWidth();
                final float viewHeight = getHeight();
                // 判断移动或缩放后，图片显示是否超出屏幕边界
                if (rect.left > 0) {
                    deltaX = -rect.left;
                }
                if (rect.top > 0) {
                    deltaY = -rect.top;
                }
                if (rect.right < viewWidth) {
                    deltaX = viewWidth - rect.right;
                }
                if (rect.bottom < viewHeight) {
                    deltaY = viewHeight - rect.bottom;
                }
                mMatrix.postTranslate(deltaX, deltaY);
            }
        }

        /**
         * 单指手势包装类
         */
        private class MySingleTouchGestureDetector {

            //是否可以拖动
            private boolean canDrag;

            private OnSingleTouchListener listener;

            private MySingleTouchGestureDetector(OnSingleTouchListener listener) {
                this.listener = listener;
            }

            public boolean onTouchEvent(MotionEvent event) {
                switch (event.getAction() & MotionEvent.ACTION_MASK) {
                    case MotionEvent.ACTION_DOWN:
                        //手指按下
                        canDrag = true;
                        listener.onTouchDown(event);
                        break;
                    case MotionEvent.ACTION_POINTER_DOWN:
                        //当屏幕上已经有触点（手指）,再有一个手指压下屏幕
                        canDrag = false;
                        break;
                    case MotionEvent.ACTION_MOVE:
                        //移动事件
                        if (canDrag) {
                            listener.onTouchMove(event);
                        }
                        break;
                    case MotionEvent.ACTION_POINTER_UP:
                        //有手指离开屏幕，但屏幕还有触点(手指)
                        canDrag = false;
                        break;
                    case MotionEvent.ACTION_UP:
                        //手指全部抬起
                        canDrag = true;
                        break;
                }
                return true;
            }
        }

        /**
         * 缩放包装类监听
         */
        private class MyScaleGestureHelper extends ScaleGestureDetector.SimpleOnScaleGestureListener {

            @Override
            public boolean onScale(ScaleGestureDetector detector) {
                float scale = getScale();
                float scaleFactor = detector.getScaleFactor();
                //缩放系数计算
                curScale = calculateScaleFactor(preScale, scaleFactor);
                //缩放比例
                mMatrix.postScale(curScale / scale, curScale / scale, detector.getFocusX(), detector.getFocusY());
                //在缩放时，进行图片显示范围的控制
                checkBorderAndCenterWhenScale();
                //分发缩放操作
                setMatrixTransform(mMatrix);

                return false;
            }

            @Override
            public boolean onScaleBegin(ScaleGestureDetector detector) {
                return true;//返回true,才会进入onScale()
            }

            @Override
            public void onScaleEnd(ScaleGestureDetector detector) {
                //缩放系数计算
                preScale = calculateScaleFactor(preScale, detector.getScaleFactor());
            }

            /**
             * <p>计算最终缩放范围<br>
             * 如果缩放范围超出规定范围（显示临界值）</p>
             */
            private float calculateScaleFactor(float oldScale, float curScale) {
                if (oldScale * curScale > SCALE_MAX) {
                    return SCALE_MAX;
                } else if (oldScale * curScale < SCALE_MIN) {
                    return SCALE_MIN;
                } else {
                    return oldScale * curScale;
                }
            }
        }
    }

    /**
     * 单指操作监听
     */
    private interface OnSingleTouchListener {
        //单指按下
        boolean onTouchDown(MotionEvent e);

        //单指移动
        boolean onTouchMove(MotionEvent e);
    }

    /**
     * 单击操作监听
     */
    public interface OnSingleClickListener {
        //单击事件
        boolean onSingleClick();
    }

    /**
     * 手势拦截操作监听
     */
    public interface OnInterceptTouchListener {
        //拦截事件
        boolean OnInterceptTouch(boolean isIntercept, MotionEvent ev);
    }
}
